package com.auxgroup.smarthome.app.entity;

import com.auxgroup.smarthome.enums.SmartModeEnum;
import com.auxgroup.smarthome.utils.NewDateUtils;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalTime;
import java.time.ZoneOffset;

/**
 *
 * @Author: laiqiuhua.
 * @Date: 2017/9/19 12:01.
 */
public class SmartElectricityRedis {
    private String deviceId;
    private String mac;
    private int startHour;
    private int startMinute;
    private int endHour;
    private int endMinute;
    private float totalElec; // 用户期望用电量
    private float surplusElec; // 剩余期望用电
    private int total; // 10 分钟用电总次数
    private int n; // 10分钟用电运行到第几次
    private int mode; // 设备模式 0：极速模式1：均衡模式 2：标准模式
    private int executeCycle; // 执行周期 0：每天执行 1：执行一次
    private boolean on; // 是否启用,0:关闭 1：启用
    private int power; // 下发功率
    private int scale; // 下发功率放大的倍速

    public SmartElectricityRedis() {}

    public SmartElectricityRedis of(String deviceId, String mac, int startHour, int startMinute, int endHour, int endMinute, float totalElec, int mode, int executeCycle, boolean on) {
        this.deviceId = deviceId;
        this.mac = mac;
        this.startHour = startHour;
        this.startMinute = startMinute;
        this.endHour = endHour;
        this.endMinute = endMinute;
        this.totalElec = totalElec;
        this.surplusElec = totalElec;
        this.mode = mode;
        this.executeCycle = executeCycle;
        this.on = on;
        return this;
    }

    public String getDeviceId() {
        return deviceId;
    }

    public void setDeviceId(String deviceId) {
        this.deviceId = deviceId;
    }

    public String getMac() {
        return mac;
    }

    public void setMac(String mac) {
        this.mac = mac;
    }

    public int getStartHour() {
        return startHour;
    }

    public void setStartHour(int startHour) {
        this.startHour = startHour;
    }

    public int getStartMinute() {
        return startMinute;
    }

    public void setStartMinute(int startMinute) {
        this.startMinute = startMinute;
    }

    public int getEndHour() {
        return endHour;
    }

    public void setEndHour(int endHour) {
        this.endHour = endHour;
    }

    public int getEndMinute() {
        return endMinute;
    }

    public void setEndMinute(int endMinute) {
        this.endMinute = endMinute;
    }

    public int getScale() {
        if(scale <=1 ) scale = 1;
        return scale;
    }

    public void setScale(int scale) {
        this.scale = scale;
    }

    public float getTotalElec() {
        return totalElec;
    }

    public void setTotalElec(float totalElec) {
        this.totalElec = totalElec;
    }

    public float getSurplusElec() {
        if(surplusElec < 0) surplusElec = 0f;
        if(surplusElec > totalElec )  {
            surplusElec = totalElec;
        }
        BigDecimal bd = new BigDecimal(surplusElec).setScale(2, BigDecimal.ROUND_HALF_UP);
        return bd.floatValue();
    }

    public void setSurplusElec(float surplusElec) {
        this.surplusElec = surplusElec;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public int getN() {
        if(n < 0)  n = 0;
        if(n >= total) n = total-1;
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }

    public int getMode() {
        return mode;
    }

    public void setMode(int mode) {
        this.mode = mode;
    }

    public int getExecuteCycle() {
        return executeCycle;
    }

    public void setExecuteCycle(int executeCycle) {
        this.executeCycle = executeCycle;
    }

    public boolean isOn() {
        return on;
    }

    public void setOn(boolean on) {
        this.on = on;
    }

    public int getPower() {
        return power;
    }

    public void setPower(int power) {
        this.power = power;
    }

    /**
     * 第一次初始化， 在开启的时候用到
     */
    public void firstInit() {
        computeExecuteCount();
        this.scale = SmartModeEnum.getSmartElectricityScale(mode);
    }

    /**
     *  如果设定每天执行，会执行此方法
     */
    public void init() {
        long executeCount =  originExecuteNumBy10Minutes();
        this.total = Long.valueOf(executeCount).intValue();
        this.n = 0;
        this.scale = SmartModeEnum.getSmartElectricityScale(mode);
    }

    /**
     * 计算执行智能用电执行次数
     * @return
     */
    private int computeExecuteCount() {
        int executeCount = 0;
        LocalTime startTime = getStartTime();
        LocalTime endTime = getEndTime();
        LocalTime now = LocalTime.now(NewDateUtils.getBeijingZoneId());
        long num = originExecuteNumBy10Minutes();
        /**
         *  存在以下几种情况：
         *  1、设置的开始时间还没到，这时候计算次数为开始时间和结束时间之差
         *  2、设置的时间已经过了，这时候以现在的时间为准计算执行次数
         *  3、结束时间已经过了
         *  其他情况均为0， 不考虑什么时候结束，因为可能由于各种原因。。。提前结束，正常结束
         */
        if(endTime.isBefore(now)) {
            executeCount = 0;
        } else if (startTime.isBefore(now) && endTime.isAfter(now)) {
            Duration nowIntervalEndTime = Duration.between(now, endTime);
            // 当前执行次数
            long nowNum = nowIntervalEndTime.toMinutes()/10;
            float percent =  nowNum * 1f/ num;
            computeSurplusElec(percent);
            executeCount = Long.valueOf(nowNum).intValue();
        } else if (startTime.isAfter(now)  && endTime.isAfter(now) ) {
            executeCount =  Long.valueOf(num).intValue();
        }
        this.total = executeCount;
        this.n = 0;
        return executeCount;
    }

    /**
     * 执行智能用电指令
     * @param execPower
     * @param electricity
     */
    public void excuteCommand(int execPower, float electricity) {
        // 每天重复执行，次数执行完毕，重新初始化，第二天执行
        if(this.getExecuteCycle() == 0 && isExecuteCycleComplete()) {
            init();
            return;
        }
        this.power = execPower;
        this.surplusElec = this.surplusElec-electricity;
        this.n = this.n+1;
        this.scale = this.scale-1;
    }

    /**
     * 是否完成一个智能用电周期
     * @return
     */
    public boolean isExecuteCycleComplete() {
        return this.getN() == (this.getTotal()-1);
    }

    /**
     * 判断是否在执行时间内
     * @return
     */
    public boolean isExecuteTime() {
        LocalTime startTime = getStartTime();
        LocalTime endTime = getEndTime();
        LocalTime now = LocalTime.now(NewDateUtils.getBeijingZoneId());
        if(startTime.compareTo(now) <= 0 && endTime.isAfter(now)) {
            return true;
        }
        return false;
    }

    /**
     * 计算用户期望用电剩余量
     * 1、用户设置时间尚未到点，初始 期望总用电量= 剩余期望用电量
     * 2、用户设置时间已经过点了，但尚在期望时间内，取剩余时间占总时间百分比* 期望总用电量
     * 3、用户设置时间不在范围，初始化为0
     * @return
     */
    private void computeSurplusElec(float percent) {
        this.setSurplusElec(this.totalElec * percent);
    }

    private LocalTime getStartTime() {
        ZoneOffset zoneOffset = ZoneOffset.of(NewDateUtils.getBeijingZoneId().getRules().getOffset(Instant.now()).getId());
        LocalTime startTime = LocalTime.of(this.startHour, this.startMinute).atOffset(zoneOffset).toLocalTime();
        return startTime;
    }

    private LocalTime getEndTime() {
        ZoneOffset zoneOffset = ZoneOffset.of(NewDateUtils.getBeijingZoneId().getRules().getOffset(Instant.now()).getId());
        LocalTime endTime = LocalTime.of(this.endHour, this.endMinute).atOffset(zoneOffset).toLocalTime();
        return endTime;
    }

    /**
     * 每十分钟执行总次数
     * @return
     */
    private long originExecuteNumBy10Minutes() {
        LocalTime startTime = getStartTime();
        LocalTime endTime =getEndTime();
        Duration duration = Duration.between(startTime, endTime);
        return duration.toMinutes()/10;
    }

}
